﻿using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Verse;

namespace Meow
{

    [StaticConstructorOnStartup]
    public class Shield : Apparel
    {
        private readonly string path = "ShieldPlease/";

        private Graphic shieldGraphic;

        private static Graphic woodenShieldGraphic = GraphicDatabase.Get<Graphic_Multi>("ShieldPlease/Epona_Shield_CavalryTargeWooden", ShaderDatabase.Cutout, new Vector2(1f, 1f), new Color(1f, 1f, 1f, 1f));

        private static readonly Vector3 drawDraftedLocNorth = new Vector3(-0.2f, -0.2f, -0.09f);

        private static readonly Vector3 drawDraftedLocSouth = new Vector3(0.2f, 0.25f, -0.15f);

        private static readonly Vector3 drawDraftedLocEast = new Vector3(0.1f, -0.25f, -0.2f);

        private static readonly Vector3 drawDraftedLocWest = new Vector3(-0.1f, 0.25f, -0.15f);

        private static readonly Vector3 drawBackLocNorth = new Vector3(0f, 0.2f, -0.2f);

        private static readonly Vector3 drawBackLocSouth = new Vector3(0f, -0.2f, -0.09f);

        private static readonly Vector3 drawBackLocEast = new Vector3(-0.15f, 0.05f, -0.07f);

        private static readonly Vector3 draWBackLocWest = new Vector3(0.15f, -2f, -0.07f);

        private const float BLOCK_RATE_FACTOR_BY_SKILL = 0.02f;

        private bool ShouldShieldUp
        {
            get
            {
                Pawn wearer = base.Wearer;
                return wearer.Spawned && (wearer.InAggroMentalState || wearer.Drafted || wearer.Drafted || (wearer.CurJob != null && wearer.CurJob.def.alwaysShowWeapon) || (wearer.mindState.duty != null && wearer.mindState.duty.def.alwaysShowWeapon));
            }
        }

        public override void PostMake()
        {
            base.PostMake();
            if (shieldGraphic != null)
            {
                return;
            }

            Action action = delegate
            {
                Color color = Color.white;
                if (def.defName != "Epona_Shield_CavalryTargeWooden")
                {
                    color = base.Stuff.stuffProps.color;
                }
                shieldGraphic = GraphicDatabase.Get<Graphic_Multi>(path + def.defName, ShaderDatabase.Cutout, def.graphicData.drawSize, color);
            };
            LongEventHandler.ExecuteWhenFinished(action);
        }

        public override void ExposeData()
        {
            base.ExposeData();
            if (Scribe.mode != LoadSaveMode.PostLoadInit)
            {
                return;
            }

            LongEventHandler.ExecuteWhenFinished(delegate
            {
                if (shieldGraphic == null)
                {
                    if (def.defName == "Epona_Shield_CavalryTargeWooden")
                    {
                        shieldGraphic = GraphicDatabase.Get<Graphic_Multi>(path + def.defName, ShaderDatabase.Cutout, def.graphicData.drawSize, Color.white);
                    }
                    else
                    {
                        shieldGraphic = GraphicDatabase.Get<Graphic_Multi>(path + def.defName, ShaderDatabase.CutoutComplex, def.graphicData.drawSize, base.Stuff.stuffProps.color);
                    }
                }
            });
        }

        public override void DrawWornExtras()
        {
            Pawn wearer = base.Wearer;
            Vector3 drawPos = wearer.DrawPos;
            if (ShouldShieldUp)
            {
                switch (wearer.Rotation.AsInt)
                {
                    case 0:
                        DrawShield(shieldGraphic.MatNorth, drawPos + drawDraftedLocNorth, 0f);
                        break;
                    case 1:
                        DrawShield(shieldGraphic.MatEast, drawPos + drawDraftedLocEast, 0f);
                        break;
                    case 2:
                        DrawShield(shieldGraphic.MatSouth, drawPos + drawDraftedLocSouth, 0f);
                        break;
                    case 3:
                        DrawShield(shieldGraphic.MatWest, drawPos + drawDraftedLocWest, 0f);
                        break;
                }
            }
            else if (!wearer.Dead && wearer.GetPosture() == PawnPosture.Standing)
            {
                switch (wearer.Rotation.AsInt)
                {
                    case 0:
                        DrawShield(shieldGraphic.MatSouth, drawPos + drawBackLocNorth, 0f);
                        break;
                    case 1:
                        DrawShield(shieldGraphic.MatWest, drawPos + drawBackLocEast, 15f);
                        break;
                    case 2:
                        DrawShield(shieldGraphic.MatNorth, drawPos + drawBackLocSouth, 0f);
                        break;
                    case 3:
                        DrawShield(shieldGraphic.MatEast, drawPos + draWBackLocWest, -15f);
                        break;
                }
            }
        }

        public void DrawShield(Material mat, Vector3 drawLoc, float angle)
        {
            Mesh plane = MeshPool.plane10;
            Graphics.DrawMesh(plane, drawLoc, Quaternion.AngleAxis(angle, Vector3.up), mat, 0);
        }

        public override bool CheckPreAbsorbDamage(DamageInfo dinfo)
        {
            Pawn wearer = base.Wearer;
            if (!wearer.Dead && !wearer.Downed)
            {
                float num = dinfo.Angle + 180f;
                float asAngle = wearer.Rotation.AsAngle;
                if (num >= 360f)
                {
                    num += -360f;
                }

                if (asAngle - num >= -70f && asAngle - num <= 70f)
                {
                    float deflectChanceByMeleeSkillLevel = GetDeflectChanceByMeleeSkillLevel(wearer.skills.GetSkill(SkillDefOf.Melee).levelInt);
                    float armorRate = 0f;
                    DamageArmorCategoryDef armorCategory = dinfo.Def.armorCategory;
                    DamageArmorCategoryDef damageArmorCategoryDef = armorCategory;
                    if (damageArmorCategoryDef != null)
                    {
                        if (damageArmorCategoryDef == DamageArmorCategoryDefOf.Sharp)
                        {
                            armorRate = this.GetStatValue(StatDefOf.ArmorRating_Sharp);
                        }
                        else
                        {
                            DamageArmorCategoryDef damageArmorCategoryDef2 = damageArmorCategoryDef;
                            if (damageArmorCategoryDef2 == DamageArmorCategoryDefOf.Blunt)
                            {
                                armorRate = this.GetStatValue(StatDefOf.ArmorRating_Blunt);
                            }
                            else
                            {
                                DamageArmorCategoryDef damageArmorCategoryDef3 = damageArmorCategoryDef;
                                if (damageArmorCategoryDef3 == DamageArmorCategoryDefOf.Heat)
                                {
                                    armorRate = this.GetStatValue(StatDefOf.ArmorRating_Heat);
                                }
                            }
                        }
                    }

                    float deflectChanceByArmorRate = GetDeflectChanceByArmorRate(armorRate);
                    float num2 = deflectChanceByMeleeSkillLevel + deflectChanceByArmorRate;
                    if (Rand.Value <= num2)
                    {
                        if (Prefs.DevMode)
                        {
                            Log.Message(wearer?.ToString() + "ShieldBlockChance".Translate() + num2.ToStringPercent());
                        }

                        MoteMaker.ThrowText(wearer.DrawPos, wearer.Map, "ShieldBlock".Translate(), 1.9f);
                        EffecterDefOf.Deflect_Metal.Spawn().Trigger(wearer, dinfo.Instigator ?? wearer);
                        return true;
                    }
                }
            }

            return false;
        }

        public override bool AllowVerbCast(Verb verb)
        {
            return !(verb is Verb_LaunchProjectile);
        }

        public override IEnumerable<StatDrawEntry> SpecialDisplayStats()
        {
            StringBuilder sharp = new StringBuilder();
            StringBuilder blunt = new StringBuilder();
            StringBuilder heat = new StringBuilder();
            float delfectChanceSharp = GetDeflectChanceByArmorRate(this.GetStatValue(StatDefOf.ArmorRating_Sharp));
            float deflectChanceBlunt = GetDeflectChanceByArmorRate(this.GetStatValue(StatDefOf.ArmorRating_Blunt));
            float deflectChanceHeat = GetDeflectChanceByArmorRate(this.GetStatValue(StatDefOf.ArmorRating_Heat));
            sharp.AppendLine("BlockChanceDefualtDesc".Translate());
            blunt.AppendLine("BlockChanceDefualtDesc".Translate());
            heat.AppendLine("BlockChanceDefualtDesc".Translate());
            float deflectChanceByMeleeSkill = 0f;
            if (Prefs.DevMode)
            {
                if (base.Wearer != null)
                {
                    int meleeSkillLevel = base.Wearer.skills.GetSkill(SkillDefOf.Melee).levelInt;
                    deflectChanceByMeleeSkill = GetDeflectChanceByMeleeSkillLevel(meleeSkillLevel);
                    sharp.AppendLine($"\n{SkillDefOf.Melee.LabelCap}({meleeSkillLevel}): {deflectChanceByMeleeSkill.ToStringPercent()}" + $"\n{StatDefOf.ArmorRating_Sharp.LabelCap}: {delfectChanceSharp.ToStringPercent()}" + string.Format("\n{0}: {1}", "StatsReport_FinalValue".Translate(), (delfectChanceSharp + deflectChanceByMeleeSkill).ToStringPercent()));
                    blunt.AppendLine($"\n{SkillDefOf.Melee.LabelCap}({meleeSkillLevel}): {deflectChanceByMeleeSkill.ToStringPercent()}" + $"\n{StatDefOf.ArmorRating_Blunt.LabelCap}: {deflectChanceBlunt.ToStringPercent()}" + string.Format("\n{0}: {1}", "StatsReport_FinalValue".Translate(), (deflectChanceBlunt + deflectChanceByMeleeSkill).ToStringPercent()));
                    heat.AppendLine($"\n{SkillDefOf.Melee.LabelCap}({meleeSkillLevel}): {deflectChanceByMeleeSkill.ToStringPercent()}" + $"\n{StatDefOf.ArmorRating_Heat.LabelCap}: {deflectChanceHeat.ToStringPercent()}" + string.Format("\n{0}: {1}", "StatsReport_FinalValue".Translate(), (deflectChanceHeat + deflectChanceByMeleeSkill).ToStringPercent()));
                }
                else
                {
                    sharp.AppendLine(string.Format("\n{0}: {1}\n{2}: {3}({4})", StatDefOf.ArmorRating_Sharp.LabelCap, this.GetStatValue(StatDefOf.ArmorRating_Sharp).ToStringPercent(), "StatsReport_FinalValue".Translate(), delfectChanceSharp.ToStringPercent(), "CanLow".Translate()));
                    blunt.AppendLine(string.Format("\n{0}: {1}\n{2}: {3}({4})", StatDefOf.ArmorRating_Blunt.LabelCap, this.GetStatValue(StatDefOf.ArmorRating_Blunt).ToStringPercent(), "StatsReport_FinalValue".Translate(), deflectChanceBlunt.ToStringPercent(), "CanLow".Translate()));
                    heat.AppendLine(string.Format("\n{0}: {1}\n{2}: {3}({4})", StatDefOf.ArmorRating_Heat.LabelCap, this.GetStatValue(StatDefOf.ArmorRating_Heat).ToStringPercent(), "StatsReport_FinalValue".Translate(), deflectChanceHeat.ToStringPercent(), "CanLow".Translate()));
                }
            }

            yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "BlockChance_Heat".Translate(), (deflectChanceHeat + deflectChanceByMeleeSkill).ToStringPercent(), heat.ToString(), 20);
            yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "BlockChance_Blunt".Translate(), (deflectChanceBlunt + deflectChanceByMeleeSkill).ToStringPercent(), blunt.ToString(), 20);
            yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "BlockChance_Sharp".Translate(), (delfectChanceSharp + deflectChanceByMeleeSkill).ToStringPercent(), sharp.ToString(), 20);
        }

        private float GetDeflectChanceByArmorRate(float armorRate)
        {
            return Mathf.Clamp01(armorRate / 2f) / 2f;
        }

        private float GetDeflectChanceByMeleeSkillLevel(int level)
        {
            return (float)level * 0.02f;
        }
    }
}
